#ifndef PHSCENENODE_H
#define PHSCENENODE_H

#include "PhSceneManager.h"
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>

using namespace std;


namespace phoenix{
//! Scenenode Prototype.
/*!
	This is the prototype for a scenenode, all scenenodes should be derived from
	this class.
*/

class PhSceneNode
	: public boost::enable_shared_from_this<PhSceneNode>
{

	protected:

        //! Scenemanager
		PhSceneManager* smanager;

		//! Depth value.
        /*!
            This value is used by the scenemanger to depth sort all drawn nodes.
            if your object does not execute the onRender() call, then it does not
            matter to you.
            \sa getDepth(), setDepth(), phoenix::PhSceneManager
        */
        float depth;

		//! Constructor.
		/*!
			The constructor only initializes the scenemanager and depth. Constructors for derived classes should
			do no more than initalize members. The create() function provides the functionality of the constructor
			for all SceneNodes.
			\sa create()
		*/
		PhSceneNode( PhSceneManager* s, const float& d = 0.0f )
			: smanager(s), depth(0.0f)
		{
		}

	public:

		//! Destructor
		/*!
			The destructor should usually not do anything.
		*/
		virtual ~PhSceneNode()
		{
		}

		//! Create
		/*!
			This is a sample create function that just returns a smart pointer to a
			new instance of the scenenode. Derived classes should overload create
			and use create as a constructor. In the create function you should do
			atleast 2 things: Allocate a new instance of your class, and add that
			instance to the scenemanager. This function shows an example of doing
			just that.
		*/
		static boost::shared_ptr<PhSceneNode> create( PhSceneManager* s )
		{
			boost::shared_ptr<PhSceneNode> newnode(new PhSceneNode(s));
			s->addNode( newnode->grab<PhSceneNode>() );
			return newnode->grab<PhSceneNode>();
		}

		//! Grab
		/*!
			This should be used to grab a pointer to an instance of PhSceneNode.
			Derived classes should call grab<DerivedNode>() when wanting a pointer
			to themselves, but when adding themselves to the scenemanager a derived
			node can call smanager->addNode( this->grab<PhSceneNode() );
		*/
		template <typename T>
		boost::shared_ptr<T> grab() { return boost::static_pointer_cast<T,PhSceneNode>( shared_from_this() ); }

		//! Drop
		/*!
			This function removes the scenenode from the scenemanager. This doesn't immediately destroy the node, but will
			release the node from being kept alive by the scenemanager.
		*/
		virtual void drop()
		{
			smanager->removeNode( this->grab<PhSceneNode>() );
		}

        //! Pre-render call.
        /*!
            All nodes in the list will have this function called by the scenemanger
            once per frame. Overloading this is required. If the scene node wants to be drawn
            it must call phoenix::PhSceneManger::registerForRendering(). You should pass
            a pointer to PhSceneNode as the argument to registerForRendering(), for example:
            smanager->registerForRendering( this->grab<PhSceneNode>() );
        */
        virtual void onPreRender()
        {}

        //! Render call.
        /*!
            Any nodes that called phoenix::PhSceneManger::registerForRendering() will first be
            sorted according to their depth, then this function is called for each node in order.
            It is highly suggested that you put any drawing code in this function. Of course, it's
            possible to draw during any of the three node passes, but this pass is the only one that is
            exclusive (Nodes must register) and is the only one that is depth sorted.
        */
        virtual void onRender()
        {}

        //! Post-render call.
        /*!
            The third render pass takes place at the end of every frame, the scene manager calls this
            function for every node in the list, and any code that should happen after everything is drawn
            should go here.
        */
        virtual void onPostRender()
        {}

        //! Set depth function.
        /*!
            Sets the depth of this node.
            \param d The new depth.
            \sa depth
        */
        inline void setDepth(const float& d) { depth = d; }

        //! Get depth function.
        /*!
            Returns the current depth of this node.
            \return Current depth.
            \sa depth
        */
        inline const float& getDepth() const { return depth; }

        //! Get scene manager.
        inline PhSceneManager* getSceneManager( ) const { return smanager; }

		//! Set scene manager.
		/*!
			\warning This does _not_ remove the node from the current scene manager, nor will it add the node to the new one.
		*/
		inline void setSceneManager( PhSceneManager* s ) { smanager = s; }

};


}//namespace phoenix

#endif // PHSCENENODE_H
